package com.example.picturebacked.manager;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.*;
import com.example.picturebacked.config.CosClientConfig;
import com.example.picturebacked.exception.BusinessException;
import com.example.picturebacked.exception.ErrorCode;
import com.example.picturebacked.exception.ThrowUtils;
import com.example.picturebacked.model.dto.file.UploadPictureResult;
import com.qcloud.cos.model.PutObjectResult;
import com.qcloud.cos.model.ciModel.persistence.ImageInfo;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.implementation.bytecode.Throw;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.List;

/**
 * 通用对象存储操作（文件上传、文件下载）
 * 可以在其他项目中直接复用
 */
@Slf4j
@Service
@Deprecated
public class FileManager {

    @Resource
    private CosManager cosManager;

    @Resource
    private CosClientConfig cosClientConfig;

    /**
     * 本地文件上传
     *
     * @param multipartFile
     * @param uploadPathPrefix
     * @return
     */
    public UploadPictureResult uploadPicture(MultipartFile multipartFile, String uploadPathPrefix) {
        // 检验图片
        validPicture(multipartFile);
        // 图片上传地址
        // 生成文件的中间随机值，防止文件名重复
        String uuid = RandomUtil.randomString(16);
        // 获取传输过来的文件名
        String originalFilename = multipartFile.getOriginalFilename();
        // 拼接文件名
        String uploadPath = String.format("/%s/%s", originalFilename, uuid);
        File temp = null;
        // 解析结果并返回
        try {
            // 创建临时文件接收
            temp = File.createTempFile(uploadPath, null);
            // 将传输过来的文件存储到临时文件中
            multipartFile.transferTo(temp);
            // 调用上传方法
            PutObjectResult putObjectResult = cosManager.putPictureObject(uploadPath, temp);
            // 通过数据万象进行获取上传图片的信息
            ImageInfo imageInfo = putObjectResult.getCiUploadResult().getOriginalInfo().getImageInfo();
            // 获取返回结果并封装
            UploadPictureResult uploadPictureResult = new UploadPictureResult();
            // 图片格式
            String format = imageInfo.getFormat();
            int width = imageInfo.getWidth();
            int height = imageInfo.getHeight();
            // 计算宽高比
            double picScale = NumberUtil.round((width * 1.0) / height, 2).doubleValue();

            uploadPictureResult.setUrl(cosClientConfig.getHost() + "/" + uploadPath);
            uploadPictureResult.setPicName(FileUtil.mainName(originalFilename));
            uploadPictureResult.setPicSize(FileUtil.size(temp));
            uploadPictureResult.setPicWidth(width);
            uploadPictureResult.setPicHeight(height);
            uploadPictureResult.setPicScale(picScale);
            uploadPictureResult.setPicFormat(format);
            return uploadPictureResult;
        } catch (IOException e) {
            log.error("上传失败 文件路径为=", uploadPath, e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "上传失败");
        } finally {
            // 临时文件清理
            extracted(temp, uploadPath);
        }
    }

    /**
     * 校验文件
     *
     * @param multipartFile
     */
    private void validPicture(MultipartFile multipartFile) {
        // 判断是否为空
        ThrowUtils.throwIf(multipartFile == null, ErrorCode.PARAMS_ERROR, "上传文件不能为空");
        // 1、校验文件大小
        long fileSize = multipartFile.getSize();
        final long ONE_MB = 1024 * 1024;
        ThrowUtils.throwIf(fileSize > 2 * (ONE_MB), ErrorCode.PARAMS_ERROR, "上传文件大小不能超过2MB");

        // 2、校验文件后缀
        String fileSuffix = FileUtil.getSuffix(multipartFile.getOriginalFilename());
        // 允许上传的文件后缀列表
        final List<String> ALLOW_FORMAT_LIST = Arrays.asList("jpg", "jpeg", "png", "gif");
        ThrowUtils.throwIf(!ALLOW_FORMAT_LIST.contains(fileSuffix), ErrorCode.PARAMS_ERROR, "上传文件格式错误");
    }

    /**
     * 清理临时文件
     *
     * @param temp       临时文件名
     * @param uploadPath 临时文件路径
     */
    public static void extracted(File temp, String uploadPath) {
        // 删除临时文件
        if (temp != null) {
            boolean del = FileUtil.del(temp);
            if (!del) {
                log.error("删除临时文件失败 filePath={}", uploadPath);
            }
        }
    }


    /**
     * 根据URL上传图片
     *
     * @param multipartFile
     * @param uploadPathPrefix
     * @return
     */

    public UploadPictureResult uploadPictureByURL(MultipartFile multipartFile, String uploadPathPrefix) {
        // 检验图片
//        validPicture(multipartFile);
        // todo 校验URL是否合法
        validPicture(multipartFile);
        // 图片上传地址
        // 生成文件的中间随机值，防止文件名重复
        String uuid = RandomUtil.randomString(16);
        // 获取传输过来的文件名
        String originalFilename = multipartFile.getOriginalFilename();
        // todo 通过URL获取图片名称

        // 拼接文件名
        String uploadPath = String.format("/%s/%s", originalFilename, uuid);
        File temp = null;
        // 解析结果并返回
        try {
            // 创建临时文件接收
            temp = File.createTempFile(uploadPath, null);

            // todo 通过URL获取图片

            // 将传输过来的文件存储到临时文件中
            multipartFile.transferTo(temp);
            // 调用上传方法
            PutObjectResult putObjectResult = cosManager.putPictureObject(uploadPath, temp);
            // 通过数据万象进行获取上传图片的信息
            ImageInfo imageInfo = putObjectResult.getCiUploadResult().getOriginalInfo().getImageInfo();
            // 获取返回结果并封装
            UploadPictureResult uploadPictureResult = new UploadPictureResult();
            // 图片格式
            String format = imageInfo.getFormat();
            int width = imageInfo.getWidth();
            int height = imageInfo.getHeight();
            // 计算宽高比
            double picScale = NumberUtil.round((width * 1.0) / height, 2).doubleValue();

            uploadPictureResult.setUrl(cosClientConfig.getHost() + "/" + uploadPath);
            uploadPictureResult.setPicName(FileUtil.mainName(originalFilename));
            uploadPictureResult.setPicSize(FileUtil.size(temp));
            uploadPictureResult.setPicWidth(width);
            uploadPictureResult.setPicHeight(height);
            uploadPictureResult.setPicScale(picScale);
            uploadPictureResult.setPicFormat(format);
            return uploadPictureResult;
        } catch (IOException e) {
            log.error("上传失败 文件路径为=", uploadPath, e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "上传失败");
        } finally {
            // 临时文件清理
            extracted(temp, uploadPath);
        }
    }

    /**
     * 校验URL
     *
     * @param fileURL
     */
    private void validPicture(String fileURL) {
        ThrowUtils.throwIf(fileURL == null, ErrorCode.PARAMS_ERROR, "上传文件不能为空");
        // 1、验证格式
        try {
            new URL(fileURL);
        } catch (MalformedURLException e) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "文件地址格式错误");
        }
        // 2、校验 URL 协议
        ThrowUtils.throwIf(!fileURL.startsWith("http://") || !fileURL.startsWith("https://"),
                ErrorCode.PARAMS_ERROR, "文件地址协议错误");

        // 3、通过发送 HEAD 请求验证文件是否存在

        HttpResponse response = null;
        try {
            response = HttpUtil.createRequest(Method.HEAD, fileURL).execute();
            // 不直接抛出异常的原因: 因为有可能目标网站不支持head请求
            if (response.getStatus() != HttpStatus.HTTP_OK) {
                return;
            }
            // 4、 校验文件类型
            String contentType = response.header("Content-Type");
            if (StrUtil.isNotBlank(contentType)) {
                // 允许的图片类型
                final List<String> ALLOW_TYPE_LIST = Arrays.asList("image/jpeg", "image/jpg", "image/png", "image/webp");
                ThrowUtils.throwIf(!ALLOW_TYPE_LIST.contains(contentType.toLowerCase()),
                        ErrorCode.PARAMS_ERROR, "文件类型错误");
            }

            // 5、校验文件大小
            String contentLenghtStr = response.header("Content-Lenght");

            if (StrUtil.isNotBlank(contentLenghtStr)) {
                try {
                    // 使用Long.parseLong()将字符串转为 long，判断上传的文件大小是否超过2MB
                    long contentLenght = Long.parseLong(contentLenghtStr);
                    final long ONE_MB = 1024 * 1024;
                    ThrowUtils.throwIf(contentLenght > 2 * (ONE_MB), ErrorCode.PARAMS_ERROR, "上传文件大小不能超过2MB");
                } catch (NumberFormatException e) {
                    throw new BusinessException(ErrorCode.PARAMS_ERROR, "文件大小格式错误");
                }
            }
        } finally {
            if (response != null) {
                response.close();
            }
        }
    }
}



























